package org.ywf.framework.proxy;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.sun.corba.se.impl.orbutil.threadpool.TimeoutException;
import lombok.extern.slf4j.Slf4j;
import org.ywf.common.converter.NullConverter;
import org.ywf.common.converter.ProxyConverter;
import org.ywf.common.entity.ConsumerDto;
import org.ywf.common.entity.RequestData;
import org.ywf.common.entity.ResponseData;
import org.ywf.framework.annotation.ProxyClient;
import org.ywf.framework.annotation.ProxyMapping;
import org.ywf.framework.core.Consumer;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

@Slf4j
public class ConsumerHandler extends ProxyInvocationHandler {

    @Override
    protected ResponseData<?> handler(Method method, RequestData<?> arg){
        return this.handler(method, arg,true);
    }

    /**
     * 1、注解判断
     * 2、请求类型转换
     * 3、数据上送
     * 4、请求结果转换
     * 6、异常处理
     * 7、日志打印
     * 8、返回数据封装
     *
     * @Author YWF
     * @Date  2023/2/6 9:19
     * @Param [method, requestData, adapt]
     **/
    protected ResponseData<?> handler(Method method, RequestData<?> requestData, boolean adapt){

        ResponseData<Object> responseData = new ResponseData();
        Object serverBody = null;
        Object resBody = null;
        ConsumerDto communicate = new ConsumerDto();
        Exception exception = null;
        System.out.println("请求参数："+requestData.toString());

        try {
            ProxyClient annotation = method.getAnnotation(ProxyClient.class);
            //代理的类
            Class<?> declaringClass = method.getDeclaringClass();
            log.info("代理的类：{}",declaringClass);
            ProxyClient client = declaringClass.getAnnotation(ProxyClient.class);
            if (client == null){
                throw new NullPointerException("无法完成请求，请检查方法上是否有ProxyClient注解");
            }
            Class<? extends Consumer> consumerInClass = client.consumerClass();
            if (annotation!=null){
                consumerInClass = annotation.consumerClass();
            }

            ProxyMapping mapping = method.getAnnotation(ProxyMapping.class);
            if (mapping == null){
                throw new NullPointerException("无法完成请求，请检查方法上是否有ProxyMapping注解");
            }
            Class<? extends ProxyConverter> convert = mapping.convert();
            ProxyConverter converter = SpringUtil.getBean(convert);
            Class returnType;
            if (converter == null){
                log.error("容器中没有找到convert实现类");
                converter = new NullConverter();
                returnType = this.getMethodReturnType(method);
            }else{
                Type[] actualTypeArguments = ((ParameterizedType) convert.getGenericInterfaces()[0]).getActualTypeArguments();
                returnType = (Class) actualTypeArguments[2];
            }

            serverBody = converter.convertReq(requestData.getBody(), requestData.getHeader());

            Consumer httpConsumer = SpringUtil.getBean(consumerInClass);
            communicate = httpConsumer.communicate(mapping, serverBody,requestData,returnType);
            Object commBody = communicate.getBody();
            resBody = converter.convertRes(commBody);

            log.info("查询结果：{}",communicate);
            responseData.setBody(resBody);
            responseData.setHeader(communicate.getHeader());
            responseData.setStatus(communicate.getStatus());
        }catch (TimeoutException e){
            exception = e;
            log.error("服务超时");
        }catch (Exception e){
            exception = e;
            log.error("程序框架错误");
        }finally {
            this.linkLog(requestData,communicate,responseData,exception);
        }
        return responseData;
    }

    private Class<?> getMethodReturnType(Method method) {
        ParameterizedType genericReturnType = (ParameterizedType) method.getGenericReturnType();
        Type[] actualTypeArguments = genericReturnType.getActualTypeArguments();
        Class<?> clazz = (Class) actualTypeArguments[0];
        return clazz;
    }

    private void linkLog(RequestData<?> requestData, ConsumerDto communicate, ResponseData<Object> responseData, Exception exception) {
        String serviceCode = requestData.getHeader().getServiceCode();
        log.info("消费者:系统标准入参->P1:[{}][{}]", serviceCode, JSONUtil.toJsonStr(requestData));
        log.info("消费者:对接系统入参->P2:[{}][{}]", serviceCode, JSONUtil.toJsonStr(communicate.getServerReq()));
        log.info("消费者:对接系统输出->R3:[{}][{}]", serviceCode, JSONUtil.toJsonStr(communicate.getServerRes()));
        log.info("消费者:系统标准输出->R4:[{}][{}]", serviceCode, JSONUtil.toJsonStr(responseData));
    }
}
